package by.zmy;

import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.*;

/**
 * 简化的 EventBus 实现
 */
public class EventBus {
    // 存储事件类型与订阅者的映射关系（线程安全）
    private final Map<Class<?>, List<Subscriber>> subscribers = new ConcurrentHashMap<>();
    // 异步任务线程池
    private final ExecutorService executor = Executors.newCachedThreadPool();

    /**
     * 注册订阅者对象（自动扫描@Subscribe方法）
     */
    public void register(Object listener) {
        for (Method method : listener.getClass().getDeclaredMethods()) {
            if (method.isAnnotationPresent(Subscribe.class)) {
                Class<?> eventType = method.getParameterTypes()[0];
                Subscribe annotation = method.getAnnotation(Subscribe.class);
                subscribers.computeIfAbsent(eventType, k -> new CopyOnWriteArrayList<>())
                        .add(new Subscriber(listener, method, annotation.async()));
            }
        }
    }

    /**
     * 发布事件
     */
    public void post(Object event) {
        List<Subscriber> subs = subscribers.get(event.getClass());
        if (subs != null) {
            for (Subscriber sub : subs) {
                if (sub.isAsync()) {
                    executor.submit(() -> sub.invoke(event)); // 异步执行
                } else {
                    sub.invoke(event); // 同步执行
                }
            }
        }
    }

    /**
     * 关闭资源（如线程池）
     */
    public void shutdown() {
        executor.shutdown();
    }

    /**
     * 订阅者封装类
     */
    private static class Subscriber {
        private final Object target;
        private final Method method;
        private final boolean async;

        public Subscriber(Object target, Method method, boolean async) {
            this.target = target;
            this.method = method;
            this.async = async;
            method.setAccessible(true);
        }

        public void invoke(Object event) {
            try {
                method.invoke(target, event);
            } catch (Exception e) {
                throw new RuntimeException("Event handling failed", e);
            }
        }

        public boolean isAsync() {
            return async;
        }
    }
}

